package com.bocloud.cmp.service.resource;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.dao.AlarmDao;
import com.bocloud.cmp.dao.CloudServerDao;
import com.bocloud.cmp.dao.CloudVendorDao;
import com.bocloud.cmp.dao.ClusterDao;
import com.bocloud.cmp.dao.DataStoreDao;
import com.bocloud.cmp.dao.FlavorDao;
import com.bocloud.cmp.dao.HostPerfDao;
import com.bocloud.cmp.dao.HostSystemDao;
import com.bocloud.cmp.dao.ImageDao;
import com.bocloud.cmp.dao.NetworkCardDao;
import com.bocloud.cmp.dao.NetworkDao;
import com.bocloud.cmp.dao.NetworkHostDao;
import com.bocloud.cmp.dao.PortDao;
import com.bocloud.cmp.dao.PortGroupDao;
import com.bocloud.cmp.dao.RegionDao;
import com.bocloud.cmp.dao.RouteDao;
import com.bocloud.cmp.dao.ServerDao;
import com.bocloud.cmp.dao.ServerIpDao;
import com.bocloud.cmp.dao.SnapshotDao;
import com.bocloud.cmp.dao.StoreHostDao;
import com.bocloud.cmp.dao.SubnetDao;
import com.bocloud.cmp.dao.VdcDao;
import com.bocloud.cmp.dao.VolumeDao;
import com.bocloud.cmp.driver.providers.intf.AlarmProvider;
import com.bocloud.cmp.driver.providers.intf.AuthProvider;
import com.bocloud.cmp.driver.providers.intf.HyperVProvider;
import com.bocloud.cmp.driver.providers.intf.LocationProvider;
import com.bocloud.cmp.entity.resource.CloudVendor;
import com.bocloud.cmp.entity.resource.HostPerf;
import com.bocloud.cmp.entity.resource.Region;
import com.bocloud.cmp.enums.VendorType;
import com.bocloud.cmp.interfaces.resource.SyncService;
import com.bocloud.cmp.model.HostPerfModel;
import com.bocloud.cmp.service.model.OperateResult;
import com.bocloud.cmp.service.thread.AlarmSyncTask;
import com.bocloud.cmp.service.utils.PercentUtil;
import com.bocloud.cmp.service.utils.ResourceEventPublisher;
import com.bocloud.cmp.service.utils.SyncOSTool;
import com.bocloud.cmp.service.utils.SyncVmwareTool;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.utils.DateTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.coordinator.harmony.HarmonyLock;
import com.bocloud.coordinator.harmony.LockFactory;

/**
 * 同步云平台service接口实现类
 * 
 * @author weiwei
 * @since 2017.02.27
 */
@Service("syncService")
public class SyncServiceImpl implements SyncService {

	private static final Logger logger = LoggerFactory.getLogger(SyncServiceImpl.class);
	@Autowired
	private ServerDao serverDao;
	@Autowired
	private VdcDao vdcDao;
	@Autowired
	private ClusterDao clusterDao;
	@Autowired
	private HostSystemDao hostSystemDao;
	@Autowired
	private DataStoreDao dataStoreDao;
	@Autowired
	private StoreHostDao storeHostDao;
	@Autowired
	private CloudServerDao cloudServerDao;
	@Autowired
	private SnapshotDao snapshotDao;
	@Autowired
	private NetworkDao networkDao;
	@Autowired
	private LocationProvider locationProvider;
	@Autowired
	private AuthProvider authProvider;
	@Autowired
	private AlarmProvider alarmProvider;
	@Autowired
	private RegionDao regionDao;
	@Autowired
	private ImageDao imageDao;
	@Autowired
	private FlavorDao flavorDao;
	@Autowired
	private SubnetDao subnetDao;
	@Autowired
	private CloudVendorDao cloudVendorDao;
	@Autowired
	private AlarmDao alarmDao;
	@Autowired
	private NetworkCardDao networkCardDao;
	@Autowired
	private VolumeDao volumeDao;
	@Autowired
	private HyperVProvider hyperVProvider;
	@Autowired
	private HostPerfDao hostPerfDao;
	@Autowired
	private PortDao portDao;
	@Autowired
	private RouteDao routeDao;
	@Autowired
	private PortGroupDao portGroupDao;
	@Autowired
	private NetworkHostDao networkHostDao;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;
	@Autowired
	private ServerIpDao serverIpDao;
	@Autowired
	private LockFactory lockFactory;

	@Override
	public BsmResult sync(Long id, Long region, Long userId) {
		try {
			CloudVendor vendor = cloudVendorDao.query(id);
			if (null == vendor) {
				return new BsmResult(false, "平台数据不存在");
			}
			return this.sync(vendor, region, userId);
		} catch (Exception e) {
			logger.error("get cloudvendor and reg error:", e);
			return new BsmResult(false, "同步失败!");
		}
	}

	/**
	 * 同步
	 * 
	 * @param vendor
	 */
	private BsmResult sync(CloudVendor vendor, Long region, Long userId) {
		VendorType type = VendorType.valueOf(vendor.getType());// 获取类型
		// 启动一个线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				String path = CloudVendor.class.getSimpleName() + "_" + vendor.getId() + "_SYNC";
				HarmonyLock lock = null;
				try {
					String operate = vendor.getType().toLowerCase() + ".sync";
					lock = lockFactory.getLock(path);
					if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
						logger.warn("Get harmonyLock time out!");
						resourceEventPublisher.send(new OperateResult(false, "获取锁失败", operate,
								MapTools.simpleMap("vendorId", vendor.getId()), userId));
						return;
					}
					logger.info("开始同步时间:" + DateTool.formatTime(new Date()));
					BsmResult result = locationProvider.sync(vendor.getUuid());
					logger.info("同步完成，开始向数据库插入数据时间" + DateTool.formatTime(new Date()));
					if (result.isSuccess()) {
						switch (type) {
						case VMWARE:
							SyncVmwareTool tool = new SyncVmwareTool(vdcDao, cloudServerDao, dataStoreDao,
									hostSystemDao, snapshotDao, networkDao, clusterDao, storeHostDao, serverDao,
									networkCardDao, portGroupDao, networkHostDao);
							result = tool.sync(vendor.getId(), result.getData(), userId);
							break;
						case OPENSTACK:
							SyncOSTool toolOS = new SyncOSTool(regionDao, cloudServerDao, hostSystemDao, serverDao,
									networkDao, subnetDao, volumeDao, snapshotDao, imageDao, flavorDao, portDao,
									routeDao, serverIpDao);
							result = toolOS.sync(vendor.getId(), result.getData(), region, userId);
							break;
						default:
							break;
						}
					}
					logger.info("数据库操作完成时间，并发送消息时间:" + DateTool.formatTime(new Date()));
					resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
							MapTools.simpleMap("vendorId", vendor.getId()), userId));
					logger.info("发送完消息时间" + DateTool.formatTime(new Date()));
				} catch (Exception e) {
					logger.error("同步失败", e);
				} finally {
					if (null != lock) {
						lock.release();
					}
				}
			}
		}).start();
		return new BsmResult(true, "同步任务已经下发，正在执行……");
	}

	@Override
	public void sync(CloudVendor vendor, Long userId) {
		List<Region> regions = null;
		try {
			regions = regionDao.list(vendor.getId());
		} catch (Exception e) {
			logger.error("sync failure:", e);
			return;
		}
		// 认证是否合法
		if (!auth(vendor.getUuid())) {
			return;
		}
		if (VendorType.VMWARE.name().equals(vendor.getType())) {
			this.sync(vendor, null, userId);
		} else if (VendorType.OPENSTACK.name().equals(vendor.getType())) {
			for (Region region : regions) {
				this.sync(vendor, region.getId(), userId);
			}
		}
	}

	@Override
	public void syncAlarm(CloudVendor vendor, Long userId) {
		// 认证是否合法
		if (!auth(vendor.getUuid())) {
			return;
		}
		new AlarmSyncTask(userId, vendor, alarmDao, alarmProvider).execute();
	}

	/**
	 * 认证
	 * 
	 * @param uuid
	 * @return
	 */
	private boolean auth(String uuid) {
		BsmResult result = authProvider.auth(uuid, null);
		return result.isSuccess();
	}

	/**
	 * @param vendor
	 */
	public void syncPerform(CloudVendor vendor) {
		BsmResult result = hyperVProvider.listPerf(vendor.getUuid());
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					if (null != result.getData()) {
						String content = JSONObject.toJSONString(result.getData());
						List<HostPerfModel> hostPerfs = JSONObject.parseArray(content, HostPerfModel.class);
						for (HostPerfModel hostPerfModel : hostPerfs) {
							HostPerf hostPerf = new HostPerf();
							hostPerf.setCpuUtil(
									PercentUtil.getPercent(hostPerfModel.getCpuUsed(), hostPerfModel.getCpuTotal()));
							hostPerf.setDiskUtil(
									PercentUtil.getPercent(hostPerfModel.getDiskUsed(), hostPerfModel.getDiskTotal()));
							hostPerf.setMemUtil(
									PercentUtil.getPercent(hostPerfModel.getMemUsed(), hostPerfModel.getMemTotal()));
							hostPerf.setIsGather(0);
							hostPerf.setVendorId(vendor.getId());
							hostPerf.setHostName(hostPerfModel.getHostName());
							hostPerf.setGmtCreate(hostPerfModel.getGmtCreate());
							hostPerfDao.save(hostPerf);
						}
					}
				} catch (Exception e) {
					logger.error("Get Message Exception:", e);
				}
			}
		}).start();
	}
}